home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / mxcode / muspl150 / adlib.c next >
C/C++ Source or Header  |  1994-10-30  |  10KB  |  401 lines

  1. /*
  2.  *    Name:        Adlib Interface Module
  3.  *    Version:    1.40
  4.  *    Author:        Vladimir Arnost (QA-Software)
  5.  *    Last revision:    Oct-30-1994
  6.  *    Compiler:    Borland C++ 3.1
  7.  *
  8.  */
  9.  
  10. /*
  11.  * Revision History:
  12.  *
  13.  *    Aug-8-1994    V1.00    V.Arnost
  14.  *        Written from scratch
  15.  *    Aug-9-1994    V1.10    V.Arnost
  16.  *        Added stereo capabilities
  17.  *    Aug-13-1994    V1.20    V.Arnost
  18.  *        Stereo capabilities made functional
  19.  *    Aug-24-1994    V1.30    V.Arnost
  20.  *        Added Adlib and SB Pro II detection
  21.  *    Oct-30-1994    V1.40    V.Arnost
  22.  *        Added BLASTER variable parsing
  23.  */
  24.  
  25. #include "adlib.h"
  26. #include <dos.h>
  27. #include <stdlib.h>
  28.  
  29. WORD AdlibPort = ADLIBPORT;
  30. WORD AdlibChannels = ADLIBCHANNELS;
  31. WORD AdlibStereo = 0;
  32.  
  33. /*
  34.  * Direct write to any Adlib/SB Pro II FM synthetiser register.
  35.  *   reg - register number (range 0x001-0x0F5 and 0x101-0x1F5). When high byte
  36.  *         of reg is zero, data go to port AdlibPort, otherwise to AdlibPort+2
  37.  *   data - register value to be written
  38.  */
  39. BYTE WriteReg(WORD reg, BYTE data)
  40. {
  41.     asm {
  42.     mov    dx,AdlibPort
  43.     mov    ax,reg
  44.     or    ah,ah
  45.     jz    out1
  46.     inc    dx
  47.     inc    dx
  48.     }
  49. out1: asm {
  50.     out    dx,al
  51.     mov    cx,6
  52.     }
  53. loop1:asm {
  54.     in    al,dx
  55.     loop    loop1
  56.  
  57.     inc    dx
  58.     mov    al,data
  59.     out    dx,al
  60.     dec    dx
  61.     mov    cx,36
  62.     }
  63. loop2:asm {
  64.     in    al,dx
  65.     loop    loop2
  66.     }
  67.     return _AL;
  68. }
  69.  
  70. /*
  71.  * Write to an operator pair. To be used for register bases of 0x20, 0x40,
  72.  * 0x60, 0x80 and 0xE0.
  73.  */
  74. void WriteChannel(BYTE regbase, BYTE channel, BYTE data1, BYTE data2)
  75. {
  76.     static BYTE adlib_op[] = {0, 1, 2, 8, 9, 10, 16, 17, 18};
  77.     static BYTE sbpro_op[] = { 0,  1,  2,   6,  7,  8,  12, 13, 14,
  78.                   18, 19, 20,  24, 25, 26,  30, 31, 32};
  79.     static WORD rg[] = {0x000,0x001,0x002,0x003,0x004,0x005,
  80.             0x008,0x009,0x00A,0x00B,0x00C,0x00D,
  81.             0x010,0x011,0x012,0x013,0x014,0x015,
  82.             0x100,0x101,0x102,0x103,0x104,0x105,
  83.             0x108,0x109,0x10A,0x10B,0x10C,0x10D,
  84.             0x110,0x111,0x112,0x113,0x114,0x115};
  85.  
  86.     if (AdlibStereo)
  87.     {
  88.     register WORD reg = sbpro_op[channel];
  89.     WriteReg(rg[reg]+regbase, data1);
  90.     WriteReg(rg[reg+3]+regbase, data2);
  91.     } else {
  92.     register WORD reg = regbase+adlib_op[channel];
  93.     WriteReg(reg, data1);
  94.     WriteReg(reg+3, data2);
  95.     }
  96. }
  97.  
  98. /*
  99.  * Write to channel a single value. To be used for register bases of
  100.  * 0xA0, 0xB0 and 0xC0.
  101.  */
  102. void WriteValue(BYTE regbase, BYTE channel, BYTE value)
  103. {
  104.     static WORD ch[] = {0x000,0x001,0x002,0x003,0x004,0x005,0x006,0x007,0x008,
  105.             0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107,0x108};
  106.     register WORD chan;
  107.  
  108.     if (AdlibStereo)
  109.     chan = ch[channel];
  110.     else
  111.     chan = channel;
  112.     WriteReg(regbase + chan, value);
  113. }
  114.  
  115. /*
  116.  * Write frequency/octave/keyon data to a channel
  117.  */
  118. void WriteFreq(BYTE channel, WORD freq, BYTE octave, BYTE keyon)
  119. {
  120.     WriteValue(0xA0, channel, (BYTE)freq);
  121.     WriteValue(0xB0, channel, *((BYTE *)&freq+1) | (octave << 2) | (keyon << 5));
  122. }
  123.  
  124. /*
  125.  * Adjust volume value (register 0x40)
  126.  */
  127. BYTE convertVolume(BYTE data, WORD volume)
  128. {
  129.     static BYTE volumetable[128] = {
  130.     0x00,0x01,0x03,0x05,0x06,0x08,0x0A,0x0B,
  131.     0x0D,0x0E,0x10,0x11,0x13,0x14,0x16,0x17,
  132.     0x19,0x1A,0x1B,0x1D,0x1E,0x20,0x21,0x22,
  133.     0x24,0x25,0x27,0x29,0x2B,0x2D,0x2F,0x31,
  134.     0x32,0x34,0x36,0x37,0x39,0x3B,0x3C,0x3D,
  135.     0x3F,0x40,0x42,0x43,0x44,0x45,0x47,0x48,
  136.     0x49,0x4A,0x4B,0x4C,0x4D,0x4F,0x50,0x51,
  137.     0x52,0x53,0x54,0x54,0x55,0x56,0x57,0x58,
  138.     0x59,0x5A,0x5B,0x5C,0x5C,0x5D,0x5E,0x5F,
  139.     0x60,0x60,0x61,0x62,0x63,0x63,0x64,0x65,
  140.     0x65,0x66,0x67,0x67,0x68,0x69,0x69,0x6A,
  141.     0x6B,0x6B,0x6C,0x6D,0x6D,0x6E,0x6E,0x6F,
  142.     0x70,0x70,0x71,0x71,0x72,0x72,0x73,0x73,
  143.     0x74,0x75,0x75,0x76,0x76,0x77,0x77,0x78,
  144.     0x78,0x79,0x79,0x7A,0x7A,0x7B,0x7B,0x7B,
  145.     0x7C,0x7C,0x7D,0x7D,0x7E,0x7E,0x7F,0x7F};
  146.     WORD n;
  147.  
  148.     if (volume > 127)
  149.     volume = 127;
  150.     n = 63 - (data & 63);
  151.     n = (n*(int)volumetable[volume]) >> 7;
  152.     n = 63 - n;
  153.     return n | (data & 0xC0);
  154. }
  155.  
  156. BYTE panVolume(WORD volume, int pan)
  157. {
  158.     if (pan >= 0)
  159.     return volume;
  160.     else
  161.     return (volume * (pan+64)) / 64;
  162. }
  163.  
  164. /*
  165.  * Write volume data to a channel
  166.  */
  167. void WriteVolume(BYTE channel, BYTE data[16], WORD volume)
  168. {
  169.     WriteChannel(0x40, channel, ((data[6] & 1) ?
  170.     (convertVolume(data[5], volume) | data[4]) : (data[5] | data[4])),
  171.     convertVolume(data[12], volume) | data[11]);
  172. }
  173.  
  174. /*
  175.  * Write pan (balance) data to a channel
  176.  */
  177. void WritePan(BYTE channel, BYTE data[16], int pan)
  178. {
  179.     BYTE bits;
  180.     if (pan < -36) bits = 0x10;        // left
  181.     else if (pan > 36) bits = 0x20;    // right
  182.     else bits = 0x30;            // both
  183.  
  184.     WriteValue(0xC0, channel, data[6] | bits);
  185. }
  186.  
  187. /*
  188.  * Write an instrument to a channel
  189.  *
  190.  * Instrument layout:
  191.  *
  192.  *   Operator1  Operator2  Descr.
  193.  *    data[0]    data[7]   reg. 0x20 - tremolo/vibrato/sustain/KSR/multi
  194.  *    data[1]    data[8]   reg. 0x60 - attack rate/decay rate
  195.  *    data[2]    data[9]   reg. 0x80 - sustain level/release rate
  196.  *    data[3]    data[10]  reg. 0xE0 - waveform select
  197.  *    data[4]    data[11]  reg. 0x40 - key scale level
  198.  *    data[5]    data[12]  reg. 0x40 - output level
  199.  *          data[6]        reg. 0xC0 - feedback/AM-FM (both operators)
  200.  */
  201. void WriteInstrument(BYTE channel, BYTE data[16])
  202. {
  203. //    WriteChannel(0x80, channel, 0x0F, 0x0F);
  204.     WriteChannel(0x40, channel, 0x3F, 0x3F);        // no volume
  205.     WriteChannel(0x20, channel, data[0], data[7]);
  206.     WriteChannel(0x60, channel, data[1], data[8]);
  207.     WriteChannel(0x80, channel, data[2], data[9]);
  208.     WriteChannel(0xE0, channel, data[3], data[10]);
  209.     WriteValue  (0xC0, channel, data[6] | 0x30);
  210. }
  211.  
  212. /*
  213.  * Initialize hardware upon startup
  214.  */
  215. void InitAdlib(WORD port, WORD stereo)
  216. {
  217.     WORD i;
  218.  
  219.     AdlibPort = port;
  220.     if ( (AdlibStereo = stereo) != 0)
  221.     {
  222.     AdlibChannels = SBPROCHANNELS;
  223.     WriteReg(0x105, 0x01);        // enable YMF262/OPL3 mode
  224.     WriteReg(0x104, 0x00);        // disable 4-operator mode
  225.     WriteReg(0x01, 0x20);        // enable Waveform Select
  226.     WriteReg(0x08, 0x40);        // turn off CSW mode
  227.     WriteReg(0xBD, 0x00);        // set vibrato/tremolo depth to low, set melodic mode
  228.     } else {
  229.     AdlibChannels = ADLIBCHANNELS;
  230.     WriteReg(0x01, 0x20);        // enable Waveform Select
  231.     WriteReg(0x08, 0x40);        // turn off CSW mode
  232.     WriteReg(0xBD, 0x00);        // set vibrato/tremolo depth to low, set melodic mode
  233.     }
  234.     for(i = 0; i < AdlibChannels; i++)
  235.     {
  236.     WriteChannel(0x40, i, 0x3F, 0x3F);    // turn off volume
  237.     WriteValue(0xB0, i, 0);            // KEY-OFF
  238.     }
  239. }
  240.  
  241. /*
  242.  * Deinitialize hardware before shutdown
  243.  */
  244. void DeinitAdlib(void)
  245. {
  246.     WORD i;
  247.  
  248.     for(i = 0; i < AdlibChannels; i++)
  249.     {
  250.     WriteChannel(0x40, i, 0x3F, 0x3F);    // turn off volume
  251.     WriteValue(0xB0, i, 0);            // KEY-OFF
  252.     }
  253.     if (AdlibStereo)
  254.     {
  255.     WriteReg(0x105, 0x00);        // disable YMF262/OPL3 mode
  256.     WriteReg(0x104, 0x00);        // disable 4-operator mode
  257.     WriteReg(0x01, 0x20);        // enable Waveform Select
  258.     WriteReg(0x08, 0x00);        // turn off CSW mode
  259.     WriteReg(0xBD, 0x00);        // set vibrato/tremolo depth to low, set melodic mode
  260.     } else {
  261.     WriteReg(0x01, 0x20);        // enable Waveform Select
  262.     WriteReg(0x08, 0x00);        // turn off CSW mode
  263.     WriteReg(0xBD, 0x00);        // set vibrato/tremolo depth to low, set melodic mode
  264.     }
  265. }
  266.  
  267. /*
  268.  * Write to a mixer register -- SP Pro only
  269.  */
  270. void SetMixer(BYTE index, BYTE data)
  271. {
  272.     if (AdlibStereo)
  273.     asm {
  274.     mov    dx,AdlibPort
  275.     add    dx,4            // port 224h - Mixer register index
  276.     mov    al,index
  277.     out    dx,al
  278.     inc    dx            // port 225h - Mixer data
  279.     mov    al,data
  280.     out    dx,al
  281.     }
  282. }
  283.  
  284. /*
  285.  * Read from a mixer register -- SP Pro only
  286.  */
  287. int GetMixer(BYTE index)
  288. {
  289.     if (AdlibStereo)
  290.     asm {
  291.     mov    dx,AdlibPort
  292.     add    dx,4            // port 224h - Mixer register index
  293.     mov    al,index
  294.     out    dx,al
  295.     inc    dx            // port 225h - Mixer data
  296.     in    al,dx
  297.     xor    ah,ah
  298.     } else
  299.     _AX = -1;
  300.     return _AX;
  301. }
  302.  
  303. /*
  304.  * Detect SB Pro mixer
  305.  */
  306. int DetectMixer(WORD port)
  307. {
  308.     WORD origPort = AdlibPort;
  309.     WORD origStereo = AdlibStereo;
  310.     WORD origvolume, volume1, volume2;
  311.  
  312.     AdlibPort = port;
  313.     AdlibStereo = 1;
  314.     origvolume = GetMixer(0x26);    // FM Volume
  315.     SetMixer(0x26, origvolume ^ 0xAA);
  316.     volume1 = GetMixer(0x26) & 0xEE;
  317.     SetMixer(0x26, origvolume ^ 0x44);
  318.     volume2 = GetMixer(0x26) & 0xEE;
  319.     SetMixer(0x26, origvolume);
  320.     AdlibPort = origPort;
  321.     AdlibStereo = origStereo;
  322.  
  323.     return ((volume1 ^ 0xAA) == (volume2 ^ 0x44));
  324. }
  325.  
  326. /*
  327.  * Detect Adlib card
  328.  */
  329. int DetectAdlib(WORD port)
  330. {
  331.     WORD origPort = AdlibPort;
  332.     WORD stat1, stat2, i;
  333.  
  334.     AdlibPort = port;
  335.     WriteReg(0x04, 0x60);
  336.     WriteReg(0x04, 0x80);
  337.     stat1 = inportb(port) & 0xE0;
  338.     WriteReg(0x02, 0xFF);
  339.     WriteReg(0x04, 0x21);
  340.     for (i = 512; --i; )
  341.     inportb(port);
  342.     stat2 = inportb(port) & 0xE0;
  343.     WriteReg(0x04, 0x60);
  344.     WriteReg(0x04, 0x80);
  345.     AdlibPort = origPort;
  346.  
  347.     return (stat1 == 0 && stat2 == 0xC0);
  348. }
  349.  
  350. /*
  351.  * Detect Sound Blaster Pro II (with OPL3)
  352.  */
  353. int DetectSBProII(WORD port)
  354. {
  355.     if (!DetectAdlib(port))
  356.     return 0;
  357.     if (!DetectMixer(port))
  358.     return 0;
  359.     if (DetectAdlib(port+2))
  360.     return 0;
  361.     return 1;
  362. }
  363.  
  364. /*
  365.  * Parse BLASTER environment variable
  366.  */
  367. int DetectBlaster(WORD *port, BYTE *irq, BYTE *dma, BYTE *type)
  368. {
  369.     const char *blaster = getenv("BLASTER");
  370.     if (!blaster) return 0;
  371.  
  372.     while (*blaster)
  373.     {
  374.     char *endpos = NULL;
  375.     long value;
  376.  
  377.     switch (*blaster++) {
  378.         case 'A':    // base I/O address
  379.         value = strtol(blaster, &endpos, 16);
  380.         if (port) *port = value;
  381.         break;
  382.         case 'I':    // IRQ number
  383.         value = strtol(blaster, &endpos, 0);
  384.         if (irq) *irq = value;
  385.         break;
  386.         case 'D':    // DMA number
  387.         value = strtol(blaster, &endpos, 0);
  388.         if (dma) *dma = value;
  389.         break;
  390.         case 'T':    // card type
  391.         value = strtol(blaster, &endpos, 0);
  392.         if (type) *type = value;
  393.         break;
  394.         // ignore anything else (spaces, ...)
  395.     }
  396.     if (endpos)
  397.         blaster = endpos;
  398.     }
  399.     return 1;
  400. }
  401.